package com.agent.vpsserver.modules.server.manager;

import com.agent.vpsserver.common.dto.AdminPageTokenRequestDTO;
import com.agent.vpsserver.common.dto.PageBean;
import com.agent.vpsserver.common.exception.BusinessException;
import com.agent.vpsserver.common.utils.RemoteCommandUtil;
import com.agent.vpsserver.common.utils.mapping.BeansUtils;
import com.agent.vpsserver.modules.server.common.constants.CommandConstant;
import com.agent.vpsserver.modules.server.entity.pojo.ServerInfoDO;
import com.agent.vpsserver.modules.server.entity.pojo.UserAccountDO;
import com.agent.vpsserver.modules.server.response.UserAccountPageResponse;
import com.agent.vpsserver.modules.server.service.ServerInfoService;
import com.agent.vpsserver.modules.server.service.UserAccountService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 用户账号信息(UserAccount)表服务实现类
 *
 * @author guochao
 * @since 2024-03-12 23:50:24
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserAccountManager  {

    private final UserAccountService userAccountService;
    private final ServerInfoService serverInfoService;
    /**
     * 保存用户
     * @param userAccount
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(UserAccountDO userAccount) {
        if (userAccount.getId() != null) {
            UserAccountDO userAccountDO = userAccountService.getById(userAccount.getId());
            if (userAccountDO == null) {
                throw new BusinessException("用户不存在");
            }
            userAccount.setSurplusBandwidth(null);
            userAccountService.updateById(userAccount);
            // 如果用户状态发生变更，对应的账号也要变更
            if (!userAccountDO.getStatus().equals(userAccount.getStatus())) {
                // 查询服务器
                ServerInfoDO serverInfo = serverInfoService.getById(userAccount.getServerId());
                if (serverInfo == null) {
                    throw new BusinessException("服务器不存在");
                }
                // 账号状态 1、正常 2、封禁 3、冻结
                if (userAccount.getStatus() == 1) {
                    this.create(serverInfo, userAccount);
                } else if (userAccount.getStatus() == 3) {
                    this.ban(serverInfo, userAccount);
                }
            }
        } else {
            userAccount.setSurplusBandwidth(userAccount.getMaxBandwidth());
            // 查询服务器
            ServerInfoDO serverInfo = serverInfoService.getById(userAccount.getServerId());
            if (serverInfo == null) {
                throw new BusinessException("服务器不存在");
            }
            if (userAccountService.getOne(new LambdaQueryWrapper<UserAccountDO>()
                    .eq(UserAccountDO::getUsername, userAccount.getUsername())
                    .eq(UserAccountDO::getServerId, userAccount.getServerId())) != null) {
                throw new BusinessException("服务器已存在相同的用户名");
            }
            userAccountService.save(userAccount);
            this.create(serverInfo, userAccount);
        }
    }

    /**
     * 创建用户
     * @param serverInfo 服务器信息
     * @param userAccount 用户信息
     */
    private void create(ServerInfoDO serverInfo, UserAccountDO userAccount) {
        String command = String.format(CommandConstant.CREATE_USER_COMMAND, userAccount.getUsername(), userAccount.getPassword());
        String remoteResponse = RemoteCommandUtil.exec(serverInfo.getHost(), serverInfo.getPort(), serverInfo.getUsername(), serverInfo.getPassword(), command);
        log.info("创建用户命令：{},结果:{}", command, remoteResponse);
        remoteResponse = RemoteCommandUtil.exec(serverInfo.getHost(), serverInfo.getPort(), serverInfo.getUsername(), serverInfo.getPassword(), command);
        log.info("重启squid结果:{}", remoteResponse);
    }

    /**
     * 封禁用户
     * @param serverInfo 服务器信息
     * @param userAccount 用户信息
     */
    private void ban(ServerInfoDO serverInfo, UserAccountDO userAccount) {
        String command = String.format(CommandConstant.REMOVE_USER_COMMAND, userAccount.getUsername());
        String remoteResponse = RemoteCommandUtil.exec(serverInfo.getHost(), serverInfo.getPort(), serverInfo.getUsername(), serverInfo.getPassword(), command);
        log.info("创建用户命令：{},结果:{}", command, remoteResponse);
        remoteResponse = RemoteCommandUtil.exec(serverInfo.getHost(), serverInfo.getPort(), serverInfo.getUsername(), serverInfo.getPassword(), command);
        log.info("重启squid结果:{}", remoteResponse);
    }

    /**
     * 分页获取用户信息
     * @param request
     * @return
     */
    public PageBean<UserAccountPageResponse> pageData(AdminPageTokenRequestDTO request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<UserAccountDO> userAccounts = userAccountService.list();
        if (CollectionUtils.isEmpty(userAccounts)) {
            return new PageBean<>();
        }
        List<UserAccountPageResponse> responseList = BeansUtils.mapList(userAccounts, UserAccountPageResponse.class);
        // 查询服务器信息
        List<Long> serverIds = responseList.stream().map(UserAccountPageResponse::getServerId).collect(Collectors.toList());
        List<ServerInfoDO> serverInfos = serverInfoService.listByIds(serverIds);
        Map<Long, ServerInfoDO> serverInfoMap = serverInfos.stream()
                .collect(Collectors.toMap(ServerInfoDO::getId, Function.identity()));
        for (UserAccountPageResponse response : responseList) {
            ServerInfoDO serverInfo = serverInfoMap.get(response.getServerId());
            if (serverInfo != null) {
                response.setServerHost(serverInfo.getHost());
                response.setServerPort(15013);
            }
        }
        PageBean<UserAccountPageResponse> pageBean = new PageBean<>();
        pageBean.setPageInfo(serverInfos);
        pageBean.setList(responseList);
        return pageBean;
    }
}
